package it.patamau.bukkit.afk;

import it.patamau.bukkit.AbstractPlugin;

import java.io.IOException;
import java.util.Collection;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;

import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Priority;
import org.bukkit.plugin.PluginManager;

/**
 * Afk for Bukkit
 *
 * @author patamau
 */
public class AfkPlugin extends AbstractPlugin {
	
    protected final AfkParameters parameters;
    private final AfkPlayerListener playerListener;
    private final AfkPlayerStats playerStats;
    private final Timer idleTimer = new Timer();

    public static final String
    	AFK_PREFIX = "[AFK] ",
    	IDLE_MESSAGE = "idle";
    public static final int
    	AFK_PREFIX_LEN = AFK_PREFIX.length();
    
    private class IdleTask extends TimerTask {
		public void run() {
			checkIdlePlayers();
		}
    }

    public AfkPlugin() {
    	super();
    	parameters = new AfkParameters(this);
    	playerListener = new AfkPlayerListener(this);        
    	playerStats = new AfkPlayerStats();
    }
    
	public void onEnable(){
		initialize(parameters);
		super.onEnable();
		try {
			parameters.load();
		} catch (IOException e) {
			log(Level.WARNING,e.getMessage());
			try {
				parameters.store();
			} catch (IOException e1) {
				log(Level.SEVERE,e1.getMessage());
			}
		}
		
        // register events
        PluginManager pm = getServer().getPluginManager();
        pm.registerEvent(Event.Type.PLAYER_JOIN, playerListener, Priority.Normal, this);
        pm.registerEvent(Event.Type.PLAYER_QUIT, playerListener, Priority.Normal, this);
        pm.registerEvent(Event.Type.PLAYER_MOVE, playerListener, Priority.Normal, this);
        pm.registerEvent(Event.Type.PLAYER_COMMAND_PREPROCESS, playerListener, Priority.Normal, this);
        //start internal threads
        idleTimer.scheduleAtFixedRate(new IdleTask(), parameters.idlechecktime, parameters.idlechecktime); 
	}
    
    private void checkIdlePlayers(){
    	long now = System.currentTimeMillis();
    	for(AfkPlayerStat pstat: playerStats.getPlayers()){
    		long time = pstat.getTime();
    		if((now-time)>parameters.idletimelimit){
    			if(!pstat.isAfk()){
    				setAfk(getServer().getPlayer(pstat.getName()), true, IDLE_MESSAGE);
    			}
    		}
    	}
    }
    
    /**
     * Tells if a player is afk
     * @param p
     * @return
     */
    public boolean isAfk(String name){
    	return playerStats.get(name).isAfk();
    }
    
    public void setAfk(Player p, boolean afk, String reason){
    	if(p==null) return; //fail safe
    	AfkPlayerStat pstat = playerStats.get(p.getName()); 
    	long now = System.currentTimeMillis();
    	boolean wasafk = pstat.isAfk();
    	if(afk){ //enable afk status  		
    		playerStats.setAfk(pstat, true, now, reason);
    		
    		if(!wasafk){
        		p.setDisplayName(AFK_PREFIX+p.getDisplayName());  
	        	broadcastMessage("afk.player.away", "{0} has gone AFK because {1}", p.getName(), reason);
    		}
    	} else { //remove afk status
    		//check time (prevent user to leave afk status too early)
    		long dt = now-pstat.getTime();
    		if(dt<parameters.sensitivity){
    			//prevent toggling too rapidly
    			return;
    		}
    		playerStats.setAfk(pstat, false, now, reason);
    		if(wasafk){
	    		int i = p.getDisplayName().indexOf(AFK_PREFIX);
	    		//only remove the prefix string
	    		if(i>=0){
	    			String head = p.getDisplayName().substring(0, i);
	    			p.setDisplayName(head+p.getDisplayName().substring(i+AFK_PREFIX_LEN));
	    		}
	    		broadcastMessage("afk.player.back", "{0} is back!", p.getName());
    		}
    	}
    }
    
    public Collection<String> getAfkPlayers(){
    	return playerStats.getAfkPlayers();
    }
    
    /**
     * Force player to be removed from the afk list
     * @param p
     */
    public AfkPlayerStat getPlayer(String name){
    	return playerStats.get(name);
    }
    
    /**
     * Force player to be removed from the afk list
     * @param p
     */
    public void removePlayer(Player p){
    	playerStats.remove(p.getName());
    }
    
    /**
     * Store properties
     */
    public void onDisable() {
    	super.onDisable();
    	playerStats.clear();
    	idleTimer.cancel();
		try {
			parameters.store();
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
}
